cmake_minimum_required(VERSION 3.15)
project(DecafLangCompiler LANGUAGES C CXX) # Enabled C and CXX

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# --- User Configuration ---
set(ANTLR4_JAR_PATH "" CACHE FILEPATH "Path to the ANTLR4 Complete JAR file")
if(NOT EXISTS "${ANTLR4_JAR_PATH}")
    message(FATAL_ERROR "ANTLR4_JAR_PATH is not set or points to a non-existent file. "
            "Please set it using -DANTLR4_JAR_PATH=/path/to/antlr-jar")
endif()
message(STATUS "Using ANTLR Jar: ${ANTLR4_JAR_PATH}")

# --- Project Settings ---
set(ANTLR_NAMESPACE "decaf_lang::parser")
set(ANTLR_GRAMMAR_NAME "DecafLang") # Base name of your .g4 file
set(GENERATED_ANTLR_DIR ${CMAKE_BINARY_DIR}/generated/antlr) # Define generated path globally

# --- Find Dependencies ---
find_package(Java REQUIRED)
message(STATUS "Found Java: ${Java_JAVA_EXECUTABLE}")

find_package(LLVM 17.0 REQUIRED CONFIG) # Requesting LLVM 17
# Use llvm-config to get the list of libraries
execute_process(
        COMMAND /opt/homebrew/opt/llvm@17/bin/llvm-config --libs core support irreader analysis bitwriter bitreader target executionengine orcjit
        OUTPUT_VARIABLE LLVM_LIBS
        OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REPLACE " " ";" LLVM_LIBS "${LLVM_LIBS}")

# Add the LLVM lib directory
link_directories(/opt/homebrew/opt/llvm@17/lib)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVM include dirs: ${LLVM_INCLUDE_DIRS}")
message(STATUS "Using LLVM library dirs: ${LLVM_LIBRARY_DIRS}")

# Find the Homebrew-installed ANTLR runtime
# This should define ANTLR4_INCLUDE_DIRS and ANTLR4_LIBRARIES or an antlr4-runtime target
find_package(antlr4-runtime REQUIRED)
message(STATUS "Found ANTLR4 Runtime via find_package")
# Add ANTLR includes globally if found via variable
if(ANTLR4_INCLUDE_DIRS)
    include_directories(${ANTLR4_INCLUDE_DIRS})
    message(STATUS "Using ANTLR4 include dirs: ${ANTLR4_INCLUDE_DIRS}")
endif()

# --- Fetch GoogleTest ---
include(FetchContent)
FetchContent_Declare(
        googletest
        GIT_REPOSITORY https://github.com/google/googletest.git
        GIT_TAG v1.14.0 # Or another release tag
)
FetchContent_MakeAvailable(googletest) # This will download/configure gtest

# --- ANTLR Code Generation Function ---
# (Keep the corrected function from previous steps that outputs to GENERATED_ANTLR_DIR)
function(generate_antlr_sources GRAMMAR_FILE GRAMMAR_NAME)
    # List of expected base filenames
    set(EXPECTED_FILENAMES
            "${GRAMMAR_NAME}Lexer.h"
            "${GRAMMAR_NAME}Lexer.cpp"
            "${GRAMMAR_NAME}Parser.h"
            "${GRAMMAR_NAME}Parser.cpp"
            "${GRAMMAR_NAME}BaseVisitor.h"
            "${GRAMMAR_NAME}BaseVisitor.cpp"
            "${GRAMMAR_NAME}Visitor.h"
            "${GRAMMAR_NAME}Visitor.cpp"
            "${GRAMMAR_NAME}.tokens"
            "${GRAMMAR_NAME}Lexer.tokens"
    )
    # Construct full paths for the OUTPUT list
    set(EXPECTED_OUTPUTS "")
    foreach(fname ${EXPECTED_FILENAMES})
        list(APPEND EXPECTED_OUTPUTS "${GENERATED_ANTLR_DIR}/${fname}")
    endforeach()

    # Custom command to run ANTLR tool
    add_custom_command(
            OUTPUT ${EXPECTED_OUTPUTS}
            COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR4_JAR_PATH}
            -Dlanguage=Cpp
            -visitor
            -o ${GENERATED_ANTLR_DIR}
            -package ${ANTLR_NAMESPACE}
            -Xexact-output-dir
            ${CMAKE_CURRENT_SOURCE_DIR}/${GRAMMAR_FILE}
            DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${GRAMMAR_FILE} ${ANTLR4_JAR_PATH}
            COMMENT "Generating ANTLR parser for ${GRAMMAR_FILE}"
            VERBATIM
    )
    # Create a custom target that depends on the generated files
    add_custom_target(antlr_generate_${GRAMMAR_NAME} DEPENDS ${EXPECTED_OUTPUTS})

    # Add the generated directory to include path globally (needed for src/tests)
    include_directories(${GENERATED_ANTLR_DIR})

endfunction()

# --- Generate Sources from Grammar ---
generate_antlr_sources(
        grammar/${ANTLR_GRAMMAR_NAME}.g4
        ${ANTLR_GRAMMAR_NAME}
        # Output variables aren't strictly needed anymore with explicit paths
)

# --- Force Generation BEFORE processing subdirectories ---
# Create a dummy target that depends on the ANTLR generation target
add_custom_target(ForceAntlrGeneration DEPENDS antlr_generate_${ANTLR_GRAMMAR_NAME})
# Add the dummy target to the default build process BEFORE subdirectories
add_custom_target(PreBuild ALL DEPENDS ForceAntlrGeneration)
link_directories(/opt/homebrew/opt/antlr4-cpp-runtime/lib)

# --- Add Subdirectories ---
# These will now be processed AFTER the ANTLR files should have been generated
add_subdirectory(src)
enable_testing()
add_subdirectory(tests)

# --- Global Settings ---
include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
